﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace SharpSoft.WPF
{
    using System.Collections;
    using System.Windows;
    using System.Windows.Controls;
    /// <summary>
    /// 为<see cref="System.Windows.Controls.ItemsControl"/>提供鼠标拖动排序的功能
    /// </summary>
    public static class ItemsControlDragExtension
    {

        public static void AttachDrag(this ItemsControl ic)
        {
            ic.AllowDrop = true;
            ic.MouseLeftButtonDown += (s, e) =>
            {
                var itemsctrl = (ItemsControl)s;
                var p = e.GetPosition(itemsctrl);
                var container = GetContainerFromPoint(itemsctrl, p);
                if (container != null)
                {
                    var index = itemsctrl.ItemContainerGenerator.IndexFromContainer(container);
                    if (index >= 0)
                    {
                        DragDrop.DoDragDrop(itemsctrl, index, DragDropEffects.Move);
                    }
                }

            };
            ic.QueryContinueDrag += (s, e) =>
            {
                var itemsctrl = (ItemsControl)s;
                var a = e.Action;

            };
            ic.Drop += (s, e) =>
            {
                var itemsctrl = (ItemsControl)s;
                var p = e.GetPosition(itemsctrl);
                var target = GetIndexFromPoint(itemsctrl, p);

                var dd = e.Data.GetData("System.Int32");
                if (dd is int source)
                {
                    BringIndexTo(itemsctrl, source, target);
                }
            };
        }

        /// <summary>
        /// 将指定索引位置的项放置到目标位置
        /// </summary>
        /// <param name="source"></param>
        /// <param name="target"></param>
        public static void BringIndexTo(this ItemsControl ic, int source, int target)
        {
            if (source == target)
            {
                return;
            }
            var item = ic.Items[source];

            var itemsSource = ic.ItemsSource;
            if (itemsSource is Array array)
            {//交换数组位置
                if (source < target)
                {
                    for (int i = source; i < target; i++)
                    {
                        array.SetValue(array.GetValue(i + 1), i);
                    }
                }
                else
                {

                    for (int i = source; i > target; i--)
                    {
                        array.SetValue(array.GetValue(i - 1), i);
                    }
                }

                array.SetValue(item, target);
            }
            else if (itemsSource is IList list)
            {//交换List的位置
                list.Remove(item);
                list.Insert(target, item);
            }

            ic.ItemsSource = null;//重置数据源
            ic.ItemsSource = itemsSource;

        }


        /// <summary>
        /// 获取<see cref="System.Windows.Controls.ItemsControl"/>指定坐标下的项目容器
        /// </summary>
        /// <param name="ic"></param>
        /// <param name="point"></param>
        /// <returns></returns>
        public static ContentPresenter GetContainerFromPoint(this ItemsControl ic, Point point)
        {
            var item = ic.InputHitTest(point);
            var c = SharpSoft.WPF.VisualHelper.FindParent<ContentPresenter>((DependencyObject)item);//找到点击项的父级ContentPresenter
            return c;
            //if (c != null)
            //{
            //    var s = ic.ItemContainerGenerator.ItemFromContainer(c);//找到点击的项
            //}
        }
        /// <summary>
        /// 获取<see cref="System.Windows.Controls.ItemsControl"/>指定坐标下的项目
        /// </summary>
        /// <param name="ic"></param>
        /// <param name="point"></param>
        /// <returns></returns>
        public static object GetItemFromPoint(this ItemsControl ic, Point point)
        {
            var c = GetContainerFromPoint(ic, point);
            if (c != null)
            {
                var s = ic.ItemContainerGenerator.ItemFromContainer(c);//找到点击的项
                return s;
            }
            return null;
        }

        /// <summary>
        /// 获取指定坐标下应该被替换的索引
        /// </summary>
        /// <param name="ic"></param>
        /// <param name="point"></param>
        /// <returns></returns>
        public static int GetIndexFromPoint(this ItemsControl ic, Point point)
        {
            if (ic.Items.Count == 0)
            {
                return 0;
            }
            var container = GetContainerFromPoint(ic, point);
            int target = ic.ItemContainerGenerator.IndexFromContainer(container);
            if (target < 0)
            {

                Dictionary<DependencyObject, Rect> dic = new Dictionary<DependencyObject, Rect>();
                foreach (var item in ic.Items)
                {//查找所有项的位置
                    var c = ic.ItemContainerGenerator.ContainerFromItem(item);
                    if (c is FrameworkElement fe)
                    {
                        dic.Add(c, new Rect(fe.TranslatePoint(new Point(0, 0), ic), new Size(fe.ActualWidth, fe.ActualHeight)));
                    }
                }
                var firstRect = dic.First().Value;
                if (point.Y < firstRect.Y || (point.X < firstRect.X && point.Y < firstRect.Y + firstRect.Height))
                {//在第一个元素之前
                    return 0;
                }
                var lastRect = dic.Last().Value;
                if (point.Y > lastRect.Y + lastRect.Height || (point.Y > lastRect.Y && point.X > lastRect.X + lastRect.Width))
                {//在最后一个元素之后
                    return ic.Items.Count - 1;
                }
            }
            else
            {
                return target;
            }
            return ic.Items.Count - 1; ;
        }

        public static bool GetAllowDrag(DependencyObject obj)
        {
            return (bool)obj.GetValue(AllowDragProperty);
        }

        public static void SetAllowDrag(DependencyObject obj, bool value)
        {
            obj.SetValue(AllowDragProperty, value);
        }
        /// <summary>
        /// 为项目容器提供一个附加属性，指定是否允许拖拽
        /// </summary>
        public static readonly DependencyProperty AllowDragProperty =
            DependencyProperty.RegisterAttached("AllowDrag", typeof(bool), typeof(ItemsControlDragExtension), new PropertyMetadata(default(bool)));


    }
}
